home *** CD-ROM | disk | FTP | other *** search
- package sub_arctic.lib;
-
- import sub_arctic.output.drawable;
- import sub_arctic.output.loaded_image;
-
- import java.awt.Color;
- import java.awt.Point;
- import java.util.Vector;
-
-
- /**
- * Class to display a line with optional arrowheads. Note: the presence of
- * the arrowheads makes it that case that the endpoints of the line are not
- * necessarily at the corners of the bounding box (consider, for example, a
- * horizontal line). This unfortunately makes use of the line with constraints
- * still a bit problematical.
- *
- * @author Scott Hudson and Ian Smith
- */
- public class line_display extends base_interactor {
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Interactor flag bit to indicate if line is negatively sloped:
- * 0,0 -> w,h [true] or positively sloped: 0,h -> w,0 [false].
- * This is computed dynamically as the x1,y1, x2,y2 coordinates of the
- * line are set. (The proper value is computed as (y2 > y1)==(x2 > x1)).
- */
- protected static final int NEG_DIAG = FIRST_FREE_FLAG;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Indicate if line is negatively sloped (i.e., to be interpreted as
- * 0,0 -> w,h rather than 0,h -> w,0).
- * @return boolean indicating negative slope.
- */
- public boolean neg_diag() {return flag_is_set(NEG_DIAG); }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Return x1 in parent's coordinate system. Note, coordinates may be
- * switched to maintain canonical form (i.e. what was originally set as
- * x2 may be reported as x1). Note this is the x1() position of the
- * line, the bound of the interactor object may extend a little further to
- * make room for an arrowhead.
- *
- * @return int x1 coordinate for the line.
- */
- public int x1() {return x();};
-
- /** Return y1 in parent's coordinate system. Note, coordinates may be
- * switched to maintain canonical form (i.e. what was originally set as
- * y2 may be reported as y1). Note this is the y1() position of the
- * line, the bound of the interactor object may extend a little further to
- * make room for an arrowhead.
- *
- * @return int y1 coordinate for the line.
- */
- public int y1()
- {
- if (flag_is_set(NEG_DIAG))
- return y();
- else
- return y()+h();
- }
-
- /** Return x2 in parent's coordinate system. Note, coordinates may be
- * switched to maintain canonical form (i.e. what was originally set as
- * x2 may be reported as x1). Note this is the x2() position of the
- * line, the bound of the interactor object may extend a little further to
- * make room for an arrowhead.
- *
- * @return int x2 coordinate for the line.
- */
- public int x2() {return x()+w();};
-
- /** Return y2 in parent's coordinate system. Note, coordinates may be
- * switched to maintain canonical form (i.e. what was originally set as
- * y2 may be reported as y1). Note this is the x1() position of the
- * line, the bound of the interactor object may extend a little further to
- * make room an arrowhead.
- *
- * @return int x2 coordinate for the line.
- */
- public int y2()
- {
- if (flag_is_set(NEG_DIAG))
- return y()+h();
- else
- return y();
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Record of line start point. */
- protected Point line_start;
-
- /** Record of line end point. */
- protected Point line_end;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Set the position of the line. Note, because of internal canonicalization,
- * the line may switch endpoints and later report what is given here as x1,y1
- * as x2,y2, and visa versa.
- *
- * @param int x1 x1 coordinate of the line (in parent's coordinate system).
- * @param int y1 y1 coordinate of the line (in parent's coordinate system).
- * @param int x1 x1 coordinate of the line (in parent's coordinate system).
- * @param int y1 y1 coordinate of the line (in parent's coordinate system).
- */
- public void set_coords(int x1, int y1, int x2, int y2)
- {
- Vector v;
- Integer x,y;
- int lowest_x, highest_x, lowest_y, highest_y;
-
- set_flag_bit(NEG_DIAG, (y2>y1)==(x2>x1));
-
- line_start=new Point(x1,y1);
- line_end=new Point(x2,y2);
-
- /* if we have arrow heads turned on, record the location of the strokes */
- if (arrow_heads()>0) {
- stroke1_start=new Point(x1,y1);
- stroke1_end=new Point(x2,y2);
-
- /* now record the locations of the arrow head points */
- v=stroke(stroke1_start.x,stroke1_start.y,
- stroke1_end.x,stroke1_end.y,
- arrow_head_length(), arrow_head_angle());
- x=(Integer)v.elementAt(0);
- y=(Integer)v.elementAt(1);
- stroke1_pt1=new Point(x.intValue(),y.intValue());
- x=(Integer)v.elementAt(2);
- y=(Integer)v.elementAt(3);
- stroke1_pt2=new Point(x.intValue(),y.intValue());
-
- /* figure out the farthest left part of this line */
- lowest_x=min(x1,x2,stroke1_pt1.x,stroke1_pt2.x);
-
- /* figure out the farthest right part of this line */
- highest_x=max(x1,x2,stroke1_pt1.x,stroke1_pt2.x);
-
- /* figure out the farthest up part of this line */
- lowest_y=min(y1,y2,stroke1_pt1.y,stroke1_pt2.y);
-
- /* figure out the farthest right part of this line */
- highest_y=max(y1,y2,stroke1_pt1.y,stroke1_pt2.y);
-
- /* is it double headed? */
- if (arrow_heads()>1) {
- stroke2_start=new Point(x2,y2);
- stroke2_end=new Point(x1,y1);
- v=stroke(stroke2_start.x,stroke2_start.y,
- stroke2_end.x,stroke2_end.y,
- arrow_head_length(), arrow_head_angle());
- x=(Integer)v.elementAt(0);
- y=(Integer)v.elementAt(1);
- stroke2_pt1=new Point(x.intValue(),y.intValue());
- x=(Integer)v.elementAt(2);
- y=(Integer)v.elementAt(3);
- stroke2_pt2=new Point(x.intValue(),y.intValue());
-
- /* figure out the farthest left part of this line */
- lowest_x=min(lowest_x,lowest_x,stroke2_pt1.x,stroke2_pt2.x);
-
- /* figure out the farthest right part of this line */
- highest_x=max(highest_x,highest_x,stroke2_pt1.x,stroke2_pt2.x);
-
- /* figure out the farthest up part of this line */
- lowest_y=min(lowest_y,lowest_y,stroke2_pt1.y,stroke2_pt2.y);
-
- /* figure out the farthest right part of this line */
- highest_y=max(highest_y,highest_y,stroke2_pt1.y,stroke2_pt2.y);
- }
- set_x(lowest_x);
- set_y(lowest_y);
- set_w(highest_x-lowest_x+1);
- set_h(highest_y-lowest_y+1);
- damage_self();
- return;
- }
-
- /* this is the case where there are no arrowheads */
- if (x2 > x1) {
- set_x(x1); set_w(x2-x1+1);
- } else {
- set_x(x2); set_w(x1 - x2 + 1);
- }
-
- if (y2 > y1) {
- set_y(y1); set_h(y2-y1+1);
- } else {
- set_y(y2); set_h(y1-y2+1);
- }
-
- damage_self();
- }
-
- //had:
- //* @exception cannot_assign if part of the object geometry is constrained.
- //* @exception general
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Constructor with arrowhead defaults.
- * @param int x1 x1 coordinate of the line.
- * @param int y1 y1 coordinate of the line.
- * @param int x2 x2 coordinate of the line.
- * @param int y2 y2 coordinate of the line.
- * @param int arrowheads the number of arrowheads to draw (must be 0,1, or 2).
- */
- public line_display(int x1, int y1, int x2, int y2, int arrowheads )
- {
- /* initialize in x,y, w,h form */
- super(0,0, 10,10);
-
- /* if arrowheads<0 or >2 there is an error */
- if ((arrowheads<0)||(arrowheads>2)) {
- throw new sub_arctic_error("Number of arrowheads must be 0, 1, or 2");
- }
-
- /* note we set this first so when we set the coords we already
- know to record the stroke info */
- set_arrow_heads(arrowheads);
-
- _arrow_head_length=20;
- _arrow_head_angle=25;
-
- /* set the real size and coords */
- set_coords(x1,y1,x2,y2);
-
- }
-
- //had:
- //* @exception general
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Full constructor.
- * @param int x1 x1 coordinate of the line.
- * @param int y1 y1 coordinate of the line.
- * @param int x2 x2 coordinate of the line.
- * @param int y2 y2 coordinate of the line.
- * @param int arrowheads the number of arrowheads to draw (must be 0,1, or 2).
- */
- public line_display(int x1, int y1, int x2, int y2, int arrowheads,
- int l, int a)
- {
- /* initialize in x,y, w,h form */
- super(0,0, 10,10);
-
- /* if arrowheads<0 or >2 there is an error */
- if ((arrowheads<0)||(arrowheads>2)) {
- throw new sub_arctic_error("Number of arrowheads must be 0, 1, or 2");
- }
- /* note we set this first so when we set the coords we already
- know to record the stroke info */
- set_arrow_heads(arrowheads);
-
- _arrow_head_length=l;
- _arrow_head_angle=a;
-
- /* set the real size and coords */
- set_coords(x1,y1,x2,y2);
-
- }
-
- //had:
- //* @exception general
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- // this should be replaced with new arrowhead infrastructure in drawable...
-
- /** Draw the image of the line */
- public void draw_self_local(drawable d) {
- Vector v;
- Integer x,y;
-
- /* draw in black */
- d.setColor(Color.black);
- d.drawLine(x_into_local(line_start.x),
- y_into_local(line_start.y),
- x_into_local(line_end.x),
- y_into_local(line_end.y));
-
- /* deal with arrow heads */
- if (arrow_heads()>0) {
-
- /* draw the 1st part of the arrowhead to the end of the 1st stroke */
- d.drawLine(x_into_local(stroke1_pt1.x),
- y_into_local(stroke1_pt1.y),
- x_into_local(stroke1_end.x),
- y_into_local(stroke1_end.y));
-
- /* draw the 2nd part of the arrowhead to the end of the 1st stroke */
- d.drawLine(x_into_local(stroke1_pt2.x),
- y_into_local(stroke1_pt2.y),
- x_into_local(stroke1_end.x),
- y_into_local(stroke1_end.y));
-
- /* dual heads? */
- if (arrow_heads()>1) {
-
- /* draw the 1st part of the arrowhead to the end of the 1st stroke */
- d.drawLine(x_into_local(stroke2_pt1.x),
- y_into_local(stroke2_pt1.y),
- x_into_local(stroke2_end.x),
- y_into_local(stroke2_end.y));
-
- /* draw the 2nd part of the arrowhead to the end of the 1st stroke */
- d.drawLine(x_into_local(stroke2_pt2.x),
- y_into_local(stroke2_pt2.y),
- x_into_local(stroke2_end.x),
- y_into_local(stroke2_end.y));
- }
- }
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /* data for drawing arrow heads */
-
- int _arrow_heads ;
-
- Point stroke1_start, stroke1_end, stroke2_start, stroke2_end;
-
- Point stroke1_pt1, stroke1_pt2, stroke2_pt1, stroke2_pt2;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Set the number of arrowheads. This must be 0, 1, or 2.
- * @param int h number of arrowheads on this line.
- */
- public void set_arrow_heads(int h) {
- _arrow_heads=h;
- }
-
- /**
- * Number of arrowheads.
- * @return int the number of arrowheads on this line.
- */
- public int arrow_heads() { return _arrow_heads;};
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * The length of the edges of the arrowhead lines.
- */
- protected int _arrow_head_length;
-
- /**
- * The length of the edges of the arrowhead lines.
- * @return int the length of the edges of the arrowhead lines.
- */
- public int arrow_head_length() { return _arrow_head_length;};
-
- /**
- * Set the length of the edges of the arrowhead lines.
- * @param int l the length of the edges of the arrowhead lines.
- */
- public void set_arrow_head_length(int l)
- {
- _arrow_head_length=l;
- set_coords(line_start.x,line_start.y,
- line_end.x, line_end.y); /* force recompute */
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * The angle (in degrees) between each of the arrowhead lines and the line
- * itself.
- */
- protected int _arrow_head_angle;
-
- /**
- * The angle (in degrees) between each of the arrowhead lines and the line
- * itself.
- * @return int angle (in degrees) between arrowhead lines and the line itself.
- */
- public int arrow_head_angle() { return _arrow_head_angle;};
-
- /**
- * Set the angle (in degrees) between each of the arrowhead lines and the line
- * itself.
- * @param int a angle (in degrees) between arrowhead lines and the line
- * itself.
- */
- public void set_arrow_head_angle(int a)
- {
- _arrow_head_angle=a;
- set_coords(line_start.x,line_start.y,
- line_end.x, line_end.y); /* force recompute */
- };
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Version of min that works over 4 ints.
- * @param int i first value.
- * @param int j second value.
- * @param int k third value.
- * @param int l third value.
- * @return int the min of those 4 values.
- */
- static int min(int i,int j,int k,int l) {
- int m=i;
- if (j<m) m=j;
- if (k<m) m=k;
- if (l<m) m=l;
- return m;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Version of max that works over 4 ints.
- * @param int i first value.
- * @param int j second value.
- * @param int k third value.
- * @param int l third value.
- * @return int the max of those 4 values.
- */
- static int max(int i,int j,int k,int l) {
- int m=i;
- if (j>m) m=j;
- if (k>m) m=k;
- if (l>m) m=l;
- return m;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- static Vector stroke(int x1, int y1, int x2, int y2, int l, int a) {
- Vector v;
- double radius, theta, p1_x, p2_x, p1_y, p2_y;
- double final_p1_x, final_p1_y, final_p2_x, final_p2_y;
- double cos_theta, sin_theta, cart_x, cart_y;
- int actual_x1, actual_y1, actual_x2, actual_y2;
-
- /* go to phase 1 ... return a 2 Integers transformed to have
- x1,y1 as the origin and x2,y2 as the point in CARTESIAN coordinates and
- the radius and angle of the x2,y2 point ...these are Floats.
- The integers you input are in an AWT coordinate system. */
- v=phase1(x1,y1,x2,y2);
-
- /* ok, got the numbers we wanted, now lets extract them */
- cart_x=(double)((Integer)v.elementAt(0)).intValue();
- cart_y=(double)((Integer)v.elementAt(1)).intValue();
- radius=((Float)v.elementAt(2)).doubleValue();
- theta=((Float)v.elementAt(3)).doubleValue();
-
- /* go to phase two. This returns two Point objects which are the two
- * points of the arrow head, assuming this arrow was along the X axis
- * pointing out and that it had the same length as the user's arrow */
- v=phase2(radius, l, a);
-
- /* ok, now we have the points, so lets rotate them about the correct
- * angle for the actual data we have */
- p1_x=((Float)v.elementAt(0)).doubleValue();
- p1_y=((Float)v.elementAt(1)).doubleValue();
- p2_x=((Float)v.elementAt(2)).doubleValue();
- p2_y=((Float)v.elementAt(3)).doubleValue();
-
- /* Phase 3:
- do the rotation about the actual theta for their line*/
- cos_theta=Math.cos((theta/360.0)*(2.0*Math.PI));
- sin_theta=Math.sin((theta/360.0)*(2.0*Math.PI));
- final_p1_x=(p1_x*cos_theta) - (p1_y * sin_theta);
- final_p1_y=(p1_x*sin_theta) + (p1_y*cos_theta);
- final_p2_x=(p2_x*cos_theta) - (p2_y*sin_theta);
- final_p2_y=(p2_x*sin_theta) + (p2_y*cos_theta);
-
- /* Phase 4:
- Do the conversion back to the AWT style coordinates ... don't
- forget to compensate for the original cartesian coords */
- final_p1_x=((double)x1)+final_p1_x;
- final_p2_x=((double)x1)+final_p2_x;
- final_p1_y=((double)y1)-final_p1_y;
- final_p2_y=((double)y1)-final_p2_y;
-
- /* convert to integers for consumption by the toolkit */
- actual_x1=(int)Math.round(final_p1_x);
- actual_y1=(int)Math.round(final_p1_y);
- actual_x2=(int)Math.round(final_p2_x);
- actual_y2=(int)Math.round(final_p2_y);
-
- /* make a vector for them */
- v=new Vector(4);
- v.addElement(new Integer(actual_x1));
- v.addElement(new Integer(actual_y1));
- v.addElement(new Integer(actual_x2));
- v.addElement(new Integer(actual_y2));
- return v;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Covert the original integer input points into 4 numbers as a vector.
- * The first two are integers, which are the cartesian coordinates of
- * x2, y2 if x1, y1 are the origin. The second two are are Floats which
- * represent the r and \theta for x2,y2 if x1,y1 are the origin. The
- * theta is in degrees, and considers the point (1,0) (cartesian) to
- * be the 0 degree point.
- */
- static Vector phase1(int x1, int y1, int x2, int y2) {
- int cartesian_x2, cartesian_y2;
- double radius, realx2, realy2, theta, degrees;
- Vector v=new Vector(4);
-
- /* possible point */
- if ((x1==x2) && (y1==y2)) {
- v.addElement(new Integer(0));
- v.addElement(new Integer(0));
- v.addElement(new Float(0.0));
- v.addElement(new Float(0.0));
- return v;
- }
-
- /* convert to cartesian, assuming x1,y1 origin */
- cartesian_x2=x2-x1;
- cartesian_y2=-(y2-y1);
-
- /* get the length of the line */
- realx2=(double)cartesian_x2;
- realy2=(double)cartesian_y2;
- radius=Math.sqrt((realx2*realx2)+(realy2*realy2));
-
- /* get the theta */
- theta=Math.atan(realy2/realx2);
-
- /* convert to degrees */
- degrees=((theta/(Math.PI/2.0))*90.0);
-
- /* now correct to get a positive angle in degrees for the
- * 2 and 4th quadrants ... also correct the angle for quad 3*/
- if (realx2<0.0) {
- /* quadrant 2 */
- degrees+=180.0;
- } else {
- /* check for quad 4 */
- if ((realx2>0.0) && (realy2<0.0)) {
- /* is quad 4 */
- degrees+=360.0;
- }
- }
-
- /* make a vector */
- v=new Vector(4);
- v.addElement(new Integer(cartesian_x2));
- v.addElement(new Integer(cartesian_y2));
- v.addElement(new Float(radius));
- v.addElement(new Float(degrees));
- return v;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * phase 2 computes the locations of the points given that
- * the arrow was along the x axis, pointing right. We know the
- * length, so we rotate about the endpoint.
- */
- static public Vector phase2(double radius, int length, int angle) {
- double angle_double=(double)angle, length_double=(double)length;
- double p1_x, p1_y, p2_x, p2_y;
- Vector v;
- double cos_angle, sin_angle;
-
- /**
- * First rotate the points about the origin to the correct spot assuming
- * the endpoint of the stroke was the origin. Since we are assuming
- * a right pointing arrow, we rotate to 180+angle and 180-angle.
- * Trick we assume a point (length, 0) and only do a 1/2
- * of the matrix multiply.
- */
- cos_angle=Math.cos(((180.0+angle_double)/360.0)*(2.0*Math.PI));
- sin_angle=Math.sin(((180.0+angle_double)/360.0)*(2.0*Math.PI));
-
- /* rotate around the origin */
- p1_x=length_double*cos_angle;
- p1_y=length_double*sin_angle;
-
- /* symmetry: x is the same, and y is just the opposite sign */
- p2_x=p1_x;
- p2_y=-p1_y;
-
- /* Ok, now shift this to the right by an amount equal to the radius */
- p1_x+=radius;
- p2_x+=radius;
-
- /* get the result ready */
- v=new Vector(4);
- v.addElement(new Float(p1_x));
- v.addElement(new Float(p1_y));
- v.addElement(new Float(p2_x));
- v.addElement(new Float(p2_y));
- return v;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
- }
- /*=========================== COPYRIGHT NOTICE ===========================
-
- This file is part of the subArctic user interface toolkit.
-
- Copyright (c) 1996 Scott Hudson and Ian Smith
- All rights reserved.
-
- The subArctic system is freely available for most uses under the terms
- and conditions described in
- http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html
- and appearing in full in the lib/interactor.java source file.
-
- The current release and additional information about this software can be
- found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
-
- ========================================================================*/
-